package com.wei.czz.framework.blog.manager;

import com.wei.czz.common.constant.Constant;
import com.wei.czz.common.constant.EntityConstant;
import com.wei.czz.common.dto.blog.audit.BlogAuditDto;
import com.wei.czz.common.dto.blog.audit.BlogAuditListDto;
import com.wei.czz.common.dto.blog.audit.BlogAuditPageEnumDto;
import com.wei.czz.common.dto.blog.audit.group.BlogAuditGroupAssignStatDto;
import com.wei.czz.common.dto.blog.audit.groupUser.BlogAuditUserAssignStatDto;
import com.wei.czz.common.dto.common.NameValue;
import com.wei.czz.common.enums.CommonEnum;
import com.wei.czz.common.enums.ResultEnum;
import com.wei.czz.common.enums.admin.user.UserMessageEnum;
import com.wei.czz.common.enums.blog.BlogLabelEnum;
import com.wei.czz.common.enums.blog.BlogStatusEnum;
import com.wei.czz.common.enums.blog.audit.AssignTypeEnum;
import com.wei.czz.common.enums.blog.audit.AuditLevelEnum;
import com.wei.czz.common.enums.blog.audit.AuditStatusEnum;
import com.wei.czz.common.enums.blog.audit.AuditTypeEnum;
import com.wei.czz.common.enums.common.multiDIct.MultiDictEnum;
import com.wei.czz.common.enums.rabbitMQ.MqEnum;
import com.wei.czz.common.exception.CzzException;
import com.wei.czz.common.po.UserPo;
import com.wei.czz.common.po.blog.audit.BlogAuditListPo;
import com.wei.czz.common.tool.PageDto;
import com.wei.czz.common.utils.CacheKeyUtils;
import com.wei.czz.common.utils.CopyUtils;
import com.wei.czz.common.utils.SecurityUtils;
import com.wei.czz.common.vo.blog.audit.BlogAuditAssignVo;
import com.wei.czz.common.vo.blog.audit.BlogAuditFormVo;
import com.wei.czz.common.vo.blog.audit.BlogAuditVo;
import com.wei.czz.framework.admin.service.UserMessageService;
import com.wei.czz.framework.admin.service.UserService;
import com.wei.czz.framework.blog.entity.*;
import com.wei.czz.framework.blog.helper.BlogAuditHelper;
import com.wei.czz.framework.blog.helper.BlogHelper;
import com.wei.czz.framework.blog.service.*;
import com.wei.czz.framework.blog.service.impl.BlogContentServiceImpl;
import com.wei.czz.framework.blog.service.impl.BlogTagServiceImpl;
import com.wei.czz.framework.common.entity.MultiDictEntity;
import com.wei.czz.framework.common.helper.CacheHelper;
import com.wei.czz.framework.common.handler.DebounceHandler;
import com.wei.czz.framework.common.helper.MultiDictHelper;
import com.wei.czz.framework.common.helper.RabbitHelper;
import com.wei.czz.framework.common.handler.redis.RedisHashHandler;
import com.wei.czz.framework.common.service.TransactionService;
import com.wei.czz.framework.rabbitMQ.message.blog.BlogAuditMessage;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * Created by IntelliJ IDEA.
 *
 * @author wyw
 * date: 2025-02-21 11:39:24
 * className: BlogAuditManager
 * version: 1.0
 * description:
 */
@Component
@AllArgsConstructor
public class BlogAuditManager {

    private static final Logger log = LoggerFactory.getLogger(BlogAuditManager.class);

    private final UserService userService;

    private final BlogService blogService;

    private final BlogStatusService blogStatusService;

    private final BlogAuditService blogAuditService;

    private final BlogAuditGroupService blogAuditGroupService;

    private final BlogAuditGroupUserService blogAuditGroupUserService;

    private final BlogAuditAssignService blogAuditAssignService;

    private final BlogAuditUserConfigService blogAuditUserConfigService;

    private final BlogContentServiceImpl blogContentService;

    private final BlogTagServiceImpl blogTagService;

    private final UserMessageService userMessageService;

    private final BlogHelper blogHelper;

    private final BlogAuditHelper blogAuditHelper;

    private final TransactionService transactionService;

    private final MultiDictHelper multiDictHelper;

    private final RedisHashHandler redisHashHandler;

    private final CacheHelper cacheHelper;

    private final DebounceHandler debounceHandler;

    private final RabbitHelper rabbitHelper;

    public PageDto<BlogAuditListDto> getBlogAuditPageList(BlogAuditFormVo blogAuditFormVo) {

        /*
            缓存请求参数
         */
        String cacheKey = CacheKeyUtils.getParamCacheKey(EntityConstant.BLOG_AUDIT);
        cacheHelper.cache(cacheKey, blogAuditFormVo);

        /*
            分页获取博客审核记录
         */
        PageDto<BlogAuditListPo> pageDto = blogService.getAuditPageList(blogAuditFormVo);
        if (pageDto.isEmpty()) {
            log.info("分页查询博客审核记录结果为空");
            return pageDto.rebuild();
        }

        List<BlogAuditListPo> blogAuditListPoList = pageDto.getList();

        // 收集用户主键
        List<Long> auditUserIdList = blogAuditListPoList.stream()
                .map(BlogAuditListPo::getAuditUserId)
                .filter(Objects::nonNull)
                .distinct()
                .collect(Collectors.toList());
        /*
            获取用户名称映射
         */
        Map<Long, String> usernameMap = userService.getNameMap(auditUserIdList, Function.identity());

        // 列表映射
        Function<BlogAuditListPo, BlogAuditListDto> function = blogAuditListPo -> {
            // 对象映射
            BlogAuditListDto blogAuditListDto = CopyUtils.map(blogAuditListPo, BlogAuditListDto.class);
            blogAuditListDto.setTypeName(AuditTypeEnum.getName(blogAuditListPo.getType()))
                    .setLevelName(AuditLevelEnum.getName(blogAuditListPo.getLevel()))
                    .setAuditUserId(
                            Optional.ofNullable(blogAuditListPo.getAuditUserId())
                                    .filter(auditUserId -> !CommonEnum.ZERO.getLongValue().equals(auditUserId))
                                    .map(Objects::toString)
                                    .orElse(null)
                    )
                    .setAuditUserName(usernameMap.get(blogAuditListPo.getAuditUserId()))
                    .setAuditStatusName(AuditStatusEnum.getName(blogAuditListPo.getAuditStatus()))
                    .setAuditRejectTypeName(multiDictHelper.findName(MultiDictEnum.BLOG_AUDIT_REJECT_TYPE, blogAuditListPo.getAuditRejectType()));
            return blogAuditListDto;
        };
        List<BlogAuditListDto> blogAuditListDtoList = CopyUtils.mapList(blogAuditListPoList, function);
        // 封装返回
        return pageDto.rebuild(blogAuditListDtoList);
    }

    public BlogAuditPageEnumDto getBlogAuditPageEnum() {

        /*
            获取页面参数
         */
        String cacheKey = CacheKeyUtils.getParamCacheKey(EntityConstant.BLOG_AUDIT);
        BlogAuditFormVo blogAuditFormVo = cacheHelper.get(cacheKey, BlogAuditFormVo.class);

        /*
            获取审核拒绝类型枚举列表
         */
        Function<MultiDictEntity, Integer> function = multiDict -> {
            try {
                return Integer.valueOf(multiDict.getValue());
            } catch (NumberFormatException e) {
                log.info("枚举值配置错误。multiDictName={} {}", multiDict.getName(), multiDict);
                throw new CzzException();
            }
        };
        List<NameValue<Integer>> auditRejectTypeList = multiDictHelper.getNameValueList(MultiDictEnum.BLOG_AUDIT_REJECT_TYPE, function);

        BlogAuditPageEnumDto blogAuditPageEnumDto = new BlogAuditPageEnumDto();
        blogAuditPageEnumDto.setBlogAuditFormVo(blogAuditFormVo)
                .setTypeList(AuditTypeEnum.getList())
                .setLevelList(AuditLevelEnum.getList())
                .setAuditStatusList(AuditStatusEnum.getList())
                .setAuditRejectTypeList(auditRejectTypeList);
        return blogAuditPageEnumDto;
    }

    public PageDto<BlogAuditListDto> getBlogSelfAuditPageList(BlogAuditFormVo blogAuditFormVo) {
        // 获取请求用户
        UserPo userPo = SecurityUtils.getUser();
        blogAuditFormVo.setAuditUserId(userPo.getUserId());

        /*
            缓存请求参数
         */
        String cacheKey = CacheKeyUtils.getParamCacheKey(EntityConstant.BLOG_AUDIT_USER);
        cacheHelper.cache(cacheKey, blogAuditFormVo);

        /*
            分页获取博客审核记录
         */
        PageDto<BlogAuditListPo> pageDto = blogService.getAuditPageList(blogAuditFormVo);
        if (pageDto.isEmpty()) {
            log.info("【我的审核】分页查询博客审核记录结果为空");
            return pageDto.rebuild();
        }

        List<BlogAuditListPo> blogAuditListPoList = pageDto.getList();

        // 列表映射
        Function<BlogAuditListPo, BlogAuditListDto> function = blogAuditListPo -> {
            // 对象映射
            BlogAuditListDto blogAuditListDto = CopyUtils.map(blogAuditListPo, BlogAuditListDto.class);
            blogAuditListDto.setTypeName(AuditTypeEnum.getName(blogAuditListPo.getType()))
                    .setLevelName(AuditLevelEnum.getName(blogAuditListPo.getLevel()))
                    .setAuditUserName(userPo.getUsername())
                    .setAuditStatusName(AuditStatusEnum.getName(blogAuditListPo.getAuditStatus()))
                    .setAuditRejectTypeName(multiDictHelper.findName(MultiDictEnum.BLOG_AUDIT_REJECT_TYPE, blogAuditListPo.getAuditRejectType()));
            return blogAuditListDto;
        };
        List<BlogAuditListDto> blogAuditListDtoList = CopyUtils.mapList(blogAuditListPoList, function);
        // 封装返回
        return pageDto.rebuild(blogAuditListDtoList);
    }

    public BlogAuditPageEnumDto getBlogSelfAuditPageEnum() {
        /*
            获取页面参数
         */
        String cacheKey = CacheKeyUtils.getParamCacheKey(EntityConstant.BLOG_AUDIT_USER);
        BlogAuditFormVo blogAuditFormVo = cacheHelper.get(cacheKey, BlogAuditFormVo.class);

        /*
            获取审核拒绝类型枚举列表
         */
        Function<MultiDictEntity, Integer> function = multiDict -> {
            try {
                return Integer.valueOf(multiDict.getValue());
            } catch (NumberFormatException e) {
                log.info("枚举值配置错误。multiDictName={} {}", multiDict.getName(), multiDict);
                throw new CzzException();
            }
        };
        List<NameValue<Integer>> auditRejectTypeList = multiDictHelper.getNameValueList(MultiDictEnum.BLOG_AUDIT_REJECT_TYPE, function);

        BlogAuditPageEnumDto blogAuditPageEnumDto = new BlogAuditPageEnumDto();
        blogAuditPageEnumDto.setBlogAuditFormVo(blogAuditFormVo)
                .setTypeList(AuditTypeEnum.getList())
                .setLevelList(AuditLevelEnum.getList())
                .setAuditStatusList(AuditStatusEnum.getList())
                .setAuditRejectTypeList(auditRejectTypeList);
        return blogAuditPageEnumDto;
    }

    public List<BlogAuditGroupAssignStatDto> getBlogAuditGroupAssignStatList() {

        /*
            获取审核用户列表
         */
        List<BlogAuditGroupUserEntity> blogAuditGroupUserList = blogAuditGroupUserService.getList();
        if (CollectionUtils.isEmpty(blogAuditGroupUserList)) {
            log.info("获取审核用户列表结果为空");
            return Collections.emptyList();
        }

        Set<Long> groupIdSet = new HashSet<>();
        Set<Long> userIdSet = new HashSet<>();
        Map<Long, List<BlogAuditGroupUserEntity>> groupUserMap = new HashMap<>();
        for (BlogAuditGroupUserEntity blogAuditGroupUser : blogAuditGroupUserList) {
            if (CommonEnum.ONE.getValue().equals(blogAuditGroupUser.getStatus())) {
                log.info("博客审核分组用户状态不可用。{}", blogAuditGroupUser);
                continue;
            }
            groupIdSet.add(blogAuditGroupUser.getGroupId());
            userIdSet.add(blogAuditGroupUser.getUserId());

            List<BlogAuditGroupUserEntity> blogAuditGroupUserEntityList = groupUserMap.computeIfAbsent(blogAuditGroupUser.getGroupId(), k -> new ArrayList<>());
            blogAuditGroupUserEntityList.add(blogAuditGroupUser);
        }
        if (groupIdSet.isEmpty()) {
            log.info("可用的博客审核分组用户列表为空");
            return Collections.emptyList();
        }

        List<Long> groupIdList = new ArrayList<>(groupIdSet);
        List<Long> userIdList = new ArrayList<>(userIdSet);

        /*
            获取审核分组列表
         */
        List<BlogAuditGroupEntity> blogAuditGroupList = blogAuditGroupService.getList(groupIdList);
        if (CollectionUtils.isEmpty(blogAuditGroupList)) {
            log.info("获取审核分组列表结果为空");
            return Collections.emptyList();
        }

        /*
            获取博客审核记录列表
         */
        List<BlogAuditEntity> blogAuditList = blogAuditService.findUserWaitAuditList(userIdList);
        Map<Long, Long> blogAuditMap = blogAuditList.stream()
                .collect(Collectors.groupingBy(BlogAuditEntity::getAuditUserId, Collectors.counting()));

        /*
            获取用户名称映射
         */
        Map<Long, String> usernameMap = userService.getNameMap(userIdList, Function.identity());

        // 列表映射
        return blogAuditGroupList.stream()
                .map(blogAuditGroup -> {

                    List<BlogAuditUserAssignStatDto> userList = groupUserMap.getOrDefault(blogAuditGroup.getId(), Collections.emptyList())
                            .stream()
                            .map(blogAuditGroupUser -> {
                                BlogAuditUserAssignStatDto blogAuditUserAssignStatDto = new BlogAuditUserAssignStatDto();
                                blogAuditUserAssignStatDto.setUserId(blogAuditGroupUser.getUserId().toString())
                                        .setUsername(usernameMap.get(blogAuditGroupUser.getUserId()))
                                        .setWaitAuditNum(blogAuditMap.getOrDefault(blogAuditGroupUser.getUserId(), 0L))
                                        .setStatus(blogAuditGroupUser.getStatus())
                                        .setStatusName(CommonEnum.getStatusName(blogAuditGroupUser.getStatus()));
                                return blogAuditUserAssignStatDto;
                            })
                            .collect(Collectors.toList());

                    BlogAuditGroupAssignStatDto blogAuditGroupAssignStatDto = new BlogAuditGroupAssignStatDto();
                    blogAuditGroupAssignStatDto.setId(blogAuditGroup.getId().toString())
                            .setName(blogAuditGroup.getName())
                            .setAuditType(blogAuditGroup.getAuditType())
                            .setAuditLevel(blogAuditGroup.getAuditLevel())
                            .setUserList(userList);

                    return blogAuditGroupAssignStatDto;
                })
                .collect(Collectors.toList());
    }

    public BlogAuditDto getWaitAuditBlog(Long id) {
        // 获取操作用户
        UserPo userPo = SecurityUtils.getUser();

        /*
            获取博客审核记录
         */
        BlogAuditEntity blogAudit;
        try {
            blogAudit = blogAuditService.get(id);
        } catch (Exception e) {
            throw new CzzException(ResultEnum.REFRESH.getCode(), "博客已不存在，请确认后重试");
        }
        // 判断用户是否是审核用户
        if (!Objects.equals(userPo.getUserId(), blogAudit.getAuditUserId())) {
            throw new CzzException(ResultEnum.REFRESH.getCode(), "您不是该博客的审核用户，请确认后重试");
        }

        /*
            获取博客
         */
        BlogEntity blog = blogHelper.getBlog(blogAudit.getBlogId());

        /*
            获取博客正文内容
         */
        BlogContentEntity blogContent = blogContentService.find(blog.getId(), blog.getVersion());

        /*
            获取博客标签
         */
        List<BlogTagEntity> blogTagList = blogTagService.findList(blog.getId(), blog.getVersion());
        List<String> tagList = CopyUtils.mapList(blogTagList, BlogTagEntity::getTagName);

        /*
            获取审核拒绝类型枚举列表
         */
        Function<MultiDictEntity, Integer> function = multiDict -> {
            try {
                return Integer.valueOf(multiDict.getValue());
            } catch (NumberFormatException e) {
                log.info("枚举值配置错误。multiDictName={} {}", multiDict.getName(), multiDict);
                throw new CzzException();
            }
        };
        List<NameValue<Integer>> auditRejectTypeList = multiDictHelper.getNameValueList(MultiDictEnum.BLOG_AUDIT_REJECT_TYPE, function);

        // 对象映射
        BlogAuditDto blogAuditDto = CopyUtils.map(blog, BlogAuditDto.class);
        blogAuditDto.setId(id.toString())
                .setBlogId(blog.getId().toString())
                .setLabelName(BlogLabelEnum.getName(blog.getLabel()))
                .setContent(blogContent.getContent())
                .setTagList(tagList)
                .setAuditRejectTypeList(auditRejectTypeList);
        return blogAuditDto;
    }

    public void blogAuditAssign(BlogAuditAssignVo blogAuditAssignVo) {
        // 获取操作用户
        UserPo userPo = SecurityUtils.getUser();
        Date date = new Date();

        List<Long> blogAuditIdList = blogAuditAssignVo.getBlogAuditIdList();

        /*
            获取博客审核记录
         */
        List<BlogAuditEntity> blogAuditList = blogAuditService.getList(blogAuditIdList);
        if (CollectionUtils.isEmpty(blogAuditList)) {
            log.info("获取博客审核记录结果为空");
            throw new CzzException(ResultEnum.ILLEGAL_FAIL);
        }
        BlogAuditEntity firstBlogAudit = blogAuditList.get(0);
        if (blogAuditList.size() > 1) {
            boolean bool = blogAuditList.stream().anyMatch(blogAudit -> {
                return !firstBlogAudit.getType().equals(blogAudit.getType()) || !firstBlogAudit.getLevel().equals(blogAudit.getLevel());
            });
            if (bool) {
                log.info("批量分配博客审核记录，所有待分配记录的审核类型或审核级必须一致");
                throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "批量分配博客审核记录，所有待分配记录的审核类型或审核级别必须一致");
            }
        }

        /*
            获取审核分组
         */
        List<BlogAuditGroupEntity> blogAuditGroupList = blogAuditGroupService.findList(
                Collections.singletonList(firstBlogAudit.getType()), Collections.singletonList(firstBlogAudit.getLevel())
        );
        if (blogAuditGroupList.isEmpty()) {
            log.info("获取审核分组结果为空");
            throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "博客审核分组不存在，请确认后重试");
        }
        // 收集审核分组主键
        List<Long> blogAuditGroupIdList = CopyUtils.mapList(blogAuditGroupList, BlogAuditGroupEntity::getId);

        /*
            获取审核分组用户
         */
        List<BlogAuditGroupUserEntity> blogAuditGroupUserList = blogAuditGroupUserService.findList(blogAuditGroupIdList);
        if (CollectionUtils.isEmpty(blogAuditGroupUserList)) {
            log.info("获取审核分组用户结果为空。blogAuditGroupIdList={}", blogAuditGroupIdList);
            throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "博客审核分组用户不存在，请确认后重试");
        }

        // 判断博客审核用户是否就在博客审核分组下
        boolean bool = blogAuditGroupUserList.stream()
                .filter(blogAuditGroupUser -> CommonEnum.ZERO.getValue().equals(blogAuditGroupUser.getStatus()))
                .noneMatch(blogAuditGroupUser -> blogAuditAssignVo.getAuditUserId().equals(blogAuditGroupUser.getUserId()));
        if (bool) {
            log.info("博客审核用户不在博客审核分组下。blogAuditGroupUserList={}", blogAuditGroupUserList);
            throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "博客审核用户不在博客审核分组下，请确认后重试");
        }

        List<BlogAuditEntity> updateBlogAuditList = new ArrayList<>();
        List<BlogAuditAssignEntity> saveBlogAuditAssignList = new ArrayList<>();
        for (BlogAuditEntity blogAudit : blogAuditList) {
            BlogAuditEntity updateBlogAudit = new BlogAuditEntity();
            updateBlogAudit.setId(blogAudit.getId())
                    .setAuditUserId(blogAuditAssignVo.getAuditUserId())
                    .setUpdateTime(date)
                    .setUpdateUser(userPo.getUsername())
                    .setUpdateUserId(userPo.getUserId());
            updateBlogAuditList.add(updateBlogAudit);

            BlogAuditAssignEntity saveBlogAuditAssign = new BlogAuditAssignEntity();
            saveBlogAuditAssign.setBlogId(blogAudit.getBlogId())
                    .setAssignType(AssignTypeEnum.HAND.getValue())
                    .setAuditType(blogAudit.getType())
                    .setAuditLevel(blogAudit.getLevel())
                    .setAuditUserId(blogAuditAssignVo.getAuditUserId())
                    .setDeleteStatus(CommonEnum.ZERO.getValue())
                    .setUpdateTime(date)
                    .setUpdateUser(StringUtils.EMPTY)
                    .setUpdateUserId(CommonEnum.ZERO.getLongValue())
                    .setCreateTime(date)
                    .setCreateUser(userPo.getUsername())
                    .setCreateUserId(userPo.getUserId());
            saveBlogAuditAssignList.add(saveBlogAuditAssign);
        }

        transactionService.execute(() -> {

            /*
                更新博客审核用户领单数量
             */
            blogAuditUserConfigService.updateClaimNum(blogAuditAssignVo.getAuditUserId(), blogAuditIdList.size());

            /*
                更新博客审核记录
             */
            blogAuditService.batchUpdate(updateBlogAuditList);

            /*
                保存博客审核分配记录
             */
            blogAuditAssignService.batchSave(saveBlogAuditAssignList);
        });
    }

    public void blogAuditTransfer(BlogAuditAssignVo blogAuditAssignVo) {
        // 获取操作用户
        UserPo userPo = SecurityUtils.getUser();
        Date date = new Date();

        List<Long> blogAuditIdList = blogAuditAssignVo.getBlogAuditIdList();

        /*
            获取博客审核记录
         */
        List<BlogAuditEntity> blogAuditList = blogAuditService.getList(blogAuditIdList);
        if (CollectionUtils.isEmpty(blogAuditList)) {
            log.info("【博客审核转派】获取博客审核记录结果为空");
            throw new CzzException(ResultEnum.ILLEGAL_FAIL);
        }
        // 审核用户映射
        Map<Long, Integer> auditUserNumMap = new HashMap<>();

        BlogAuditEntity firstBlogAudit = blogAuditList.get(0);
        for (BlogAuditEntity blogAudit : blogAuditList) {
            if (CommonEnum.ZERO.getLongValue().equals(blogAudit.getAuditUserId())) {
                log.info("博客审核记录未分配。blogAudit={}", blogAudit);
                throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "批量转派博客审核记录，存在未分配记录，请确认后重试");
            }
            if (!firstBlogAudit.getType().equals(blogAudit.getType())) {
                log.info("批量转派博客审核记录，所有待分配记录的审核类型必须一致");
                throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "批量转派博客审核记录，所有待转派记录的审核类型必须一致");
            }
            if (!firstBlogAudit.getLevel().equals(blogAudit.getLevel())) {
                log.info("批量转派博客审核记录，所有待分配记录的审核级别必须一致");
                throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "批量转派博客审核记录，所有待转派记录的审核级别必须一致");
            }
            // 收集审核用户
            Integer auditNum = auditUserNumMap.computeIfAbsent(blogAudit.getAuditUserId(), k -> 0);
            auditUserNumMap.put(blogAudit.getAuditUserId(), auditNum + 1);
        }

        /*
            获取审核分组
         */
        List<BlogAuditGroupEntity> blogAuditGroupList = blogAuditGroupService.findList(
                Collections.singletonList(firstBlogAudit.getType()), Collections.singletonList(firstBlogAudit.getLevel())
        );
        if (blogAuditGroupList.isEmpty()) {
            log.info("【博客审核转派】获取审核分组结果为空");
            throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "博客审核分组不存在，请确认后重试");
        }
        // 收集审核分组主键
        List<Long> blogAuditGroupIdList = CopyUtils.mapList(blogAuditGroupList, BlogAuditGroupEntity::getId);

        /*
            获取审核分组用户
         */
        List<BlogAuditGroupUserEntity> blogAuditGroupUserList = blogAuditGroupUserService.findList(blogAuditGroupIdList);
        if (CollectionUtils.isEmpty(blogAuditGroupUserList)) {
            log.info("【博客审核转派】获取审核分组用户结果为空。blogAuditGroupIdList={}", blogAuditGroupIdList);
            throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "博客审核分组用户不存在，请确认后重试");
        }

        // 判断博客审核用户是否就在博客审核分组下
        boolean bool = blogAuditGroupUserList.stream()
                .filter(blogAuditGroupUser -> CommonEnum.ZERO.getValue().equals(blogAuditGroupUser.getStatus()))
                .noneMatch(blogAuditGroupUser -> blogAuditAssignVo.getAuditUserId().equals(blogAuditGroupUser.getUserId()));
        if (bool) {
            log.info("【博客审核转派】博客审核用户不在博客审核分组下。blogAuditGroupUserList={}", blogAuditGroupUserList);
            throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "博客审核用户不在博客审核分组下，请确认后重试");
        }

        List<BlogAuditEntity> updateBlogAuditList = new ArrayList<>();
        List<BlogAuditAssignEntity> saveBlogAuditAssignList = new ArrayList<>();
        for (BlogAuditEntity blogAudit : blogAuditList) {
            BlogAuditEntity updateBlogAudit = new BlogAuditEntity();
            updateBlogAudit.setId(blogAudit.getId())
                    .setAuditUserId(blogAuditAssignVo.getAuditUserId())
                    .setUpdateTime(date)
                    .setUpdateUser(userPo.getUsername())
                    .setUpdateUserId(userPo.getUserId());
            updateBlogAuditList.add(updateBlogAudit);

            BlogAuditAssignEntity saveBlogAuditAssign = new BlogAuditAssignEntity();
            saveBlogAuditAssign.setBlogId(blogAudit.getBlogId())
                    .setAssignType(AssignTypeEnum.HAND.getValue())
                    .setAuditType(blogAudit.getType())
                    .setAuditLevel(blogAudit.getLevel())
                    .setAuditUserId(blogAuditAssignVo.getAuditUserId())
                    .setDeleteStatus(CommonEnum.ZERO.getValue())
                    .setUpdateTime(date)
                    .setUpdateUser(StringUtils.EMPTY)
                    .setUpdateUserId(CommonEnum.ZERO.getLongValue())
                    .setCreateTime(date)
                    .setCreateUser(userPo.getUsername())
                    .setCreateUserId(userPo.getUserId());
            saveBlogAuditAssignList.add(saveBlogAuditAssign);
        }

        transactionService.execute(() -> {

            /*
                更新博客审核用户领单数量
             */
            blogAuditUserConfigService.updateClaimNum(blogAuditAssignVo.getAuditUserId(), blogAuditIdList.size());

            for (Map.Entry<Long, Integer> entry : auditUserNumMap.entrySet()) {
                Long userId = entry.getKey();
                Integer num = entry.getValue();

                /*
                    更新博客审核用户领单数量
                 */
                blogAuditUserConfigService.updateClaimNum(userId, -num);
            }

            /*
                更新博客审核记录
             */
            blogAuditService.batchUpdate(updateBlogAuditList);

            /*
                保存博客审核分配记录
             */
            blogAuditAssignService.batchSave(saveBlogAuditAssignList);

        });

    }

    public void blogAudit(BlogAuditVo blogAuditVo) {
        // 获取操作用户
        UserPo userPo = SecurityUtils.getUser();
        Date date = new Date();

        /*
            获取博客
         */
        BlogEntity blog = blogHelper.getBlog(blogAuditVo.getBlogId());
        if (!BlogStatusEnum.getAuditStatusList().contains(blog.getStatus())) {
            log.info("博客当前状态不是审核状态。status={}", BlogStatusEnum.getName(blog.getStatus()));
            throw new CzzException(ResultEnum.REFRESH.getCode(), "博客当前状态不是审核状态，请确认后重新操作");
        }

        /*
            获取博客审核记录
         */
        BlogAuditEntity blogAudit = blogAuditService.get(blogAuditVo.getId());
        if (!Objects.equals(userPo.getUserId(), blogAudit.getAuditUserId())) {
            log.info("操作用户不是博客审核用户");
            throw new CzzException(ResultEnum.REFRESH.getCode(), "您不是该博客的审核用户，请确认后重新操作");
        }
        // 判断博客审核级别是否是一审
        boolean isOneLevel = AuditLevelEnum.ONE.getValue().equals(blogAudit.getLevel());

        // 博客状态
        Integer status = BlogStatusEnum.AUDIT_PASS.getValue();
        Integer auditType;
        boolean isAuditReject = AuditStatusEnum.REJECT.getValue().equals(blogAuditVo.getAuditStatus());
        if (Objects.equals(blog.getStatus(), BlogStatusEnum.AUDIT.getValue())) {
            if (isAuditReject) {
                // 新博客审核拒绝
                status = BlogStatusEnum.AUDIT_REJECT.getValue();
            }
            // 新博客审核
            auditType = AuditTypeEnum.NEW_BLOG.getValue();
        } else if (Objects.equals(blog.getStatus(), BlogStatusEnum.EDIT_AUDIT.getValue())) {
            if (isAuditReject) {
                // 博客编辑审核拒绝
                status = BlogStatusEnum.EDIT_AUDIT_REJECT.getValue();
            }
            // 博客编辑审核
            auditType = AuditTypeEnum.UPDATE_BLOG.getValue();
        } else if (Objects.equals(blog.getStatus(), BlogStatusEnum.APPEAL_AUDIT.getValue())) {
            if (isAuditReject) {
                // 博客申诉审核拒绝
                status = BlogStatusEnum.APPEAL_AUDIT_REJECT.getValue();
            }
            // 博客申诉审核
            auditType = AuditTypeEnum.APPEAL_BLOG.getValue();
        } else {
            log.info("博客审核类型匹配逻辑未实现。status={}", BlogStatusEnum.getName(blog.getStatus()));
            throw new CzzException(ResultEnum.REFRESH.getCode(), "博客审核类型匹配逻辑未实现，请联系管理员");
        }

        // 修改博客
        BlogEntity editBlog = new BlogEntity();
        editBlog.setId(blogAudit.getBlogId())
                .setStatus(status)
                .setUpdateTime(date)
                .setUpdateUser(userPo.getUsername())
                .setUpdateUserId(userPo.getUserId());

        // 修改博客状态
        BlogStatusEntity saveBlogStatus = new BlogStatusEntity();
        saveBlogStatus.setBlogId(blogAudit.getBlogId())
                .setAuditId(blogAuditVo.getId())
                .setPreStatus(blog.getStatus())
                .setCurStatus(editBlog.getStatus())
                .setRemark(StringUtils.EMPTY);

        // 修改博客审核记录
        BlogAuditEntity editBlogAudit = new BlogAuditEntity();
        editBlogAudit.setId(blogAudit.getId())
                .setAuditTime(date)
                .setAuditStatus(blogAuditVo.getAuditStatus())
                .setAuditRejectType(blogAuditVo.getAuditRejectType())
                .setAuditRemark(Optional.ofNullable(blogAuditVo.getAuditRemark()).orElse(StringUtils.EMPTY));

        // 保存新博客审核记录
        BlogAuditEntity saveBlogAudit = new BlogAuditEntity();
        if (isOneLevel) {
            saveBlogAudit.setBlogId(blog.getId())
                    .setType(auditType)
                    .setLevel(AuditLevelEnum.TWO.getValue())
                    .setAuditUserId(CommonEnum.ZERO.getLongValue())
                    .setAuditStatus(AuditStatusEnum.WAIT.getValue())
                    .setAuditRejectType(CommonEnum.MINUS_ONE.getValue())
                    .setAuditRemark(StringUtils.EMPTY)
                    .setRemark(StringUtils.EMPTY);
        }

        String redisKey = CacheKeyUtils.getRedisHashKey(EntityConstant.BLOG);
        String hashKey = blog.getId().toString();
        Long count = redisHashHandler.delete(redisKey, hashKey);
        log.info("【博客审核】删除缓存成功。count={}", count);

        StringBuilder sb = new StringBuilder();
        sb.append("您的博客‘");
        sb.append(blog.getTitle());
        sb.append("’");
        if (BlogStatusEnum.AUDIT_PASS.getValue().equals(status)) {
            sb.append("审核通过，您可以操作发布");
        } else {
            sb.append("审核拒绝，您可以编辑后重新提交审核");
        }

        transactionService.execute(() -> {
            /*
                更新博客
             */
            blogService.edit(editBlog);

            /*
                保存博客状态记录
             */
            blogStatusService.saveOrEdit(saveBlogStatus);

            /*
                更新博客审核记录
             */
            blogAuditService.saveOrEdit(editBlogAudit);

            if (isOneLevel) {
                blogAuditService.saveOrEdit(saveBlogAudit);
            }

            /*
                更新博客审核用户审核数量
             */
            blogAuditUserConfigService.updateAuditNum(blogAudit.getAuditUserId(), 1);

            /*
                给用户发送消息
             */
            userMessageService.saveUserMessage(blog.getUserId(), userPo.getUserId(),
                    UserMessageEnum.SYSTEM_MSG.getValue(), "博客审核结果", sb.toString());
        });

        if (isOneLevel) {
            // 发送审核MQ消息
            BlogAuditMessage blogAuditMessage = new BlogAuditMessage();
            blogAuditMessage.setAuditId(saveBlogAudit.getId())
                    .setBlogId(blog.getId())
                    .setAuditType(auditType)
                    .setAuditLevel(AuditLevelEnum.TWO.getValue());
            rabbitHelper.send(MqEnum.BLOG_AUDIT, blogAuditMessage);
        }

        // 延时双删
        Runnable runnable = () -> {
            Long _count = redisHashHandler.delete(redisKey, hashKey);
            log.info("【博客审核】延时双删缓存成功。count={}", _count);
        };
        debounceHandler.debounceRun(runnable, redisKey + Constant.SPLIT + hashKey, 1500, TimeUnit.MILLISECONDS);

    }
}
